package gepetto.command;

import gepetto.util.LNodeList;

import java.util.TreeMap;



public class CommandHistory {
	private boolean redoable;

	private boolean undoable;

	private LNodeList<Command> history;

	private TreeMap<String, Command> protos;

	public CommandHistory() {
		undoable = redoable = false;
		history = new LNodeList<Command>();
		protos = new TreeMap<String, Command>();
	}
	
	public Command make (String cmdname) {
		if (protos.containsKey(cmdname)) {
			return protos.get(cmdname).clone();
		}
		return null;
	}

	public void exec(String cmdname) {
		if (protos.containsKey(cmdname)) {
			Command cmd = protos.get(cmdname).clone();
			this.exec(cmd);
		}
	}

	public void exec(Command cmd) {
		if (cmd.update() && cmd.redo()) {
			history.clearToTail();
			history.pushTail(cmd);
			history.currentNext();
			undoable = true;
			redoable = false;
		}
	}

	public void undo() {
		if (undoable && ! history.isEmpty()) {
			Command cmd = history.getCurrent();
			cmd.undo();
			redoable = true;
			if (history.hasPrevious()) {
				history.currentPrevious();
			}
			else {
				undoable = false;
			}
		}
	}

	public void redo() {
		if (redoable && ! history.isEmpty()) {
			Command cmd;
			if (! undoable) {
				cmd = history.getCurrent();
			}
			else if (history.hasNext()) {
				history.currentNext();
				cmd = history.getCurrent();
			}
			else {
				return;
			}
			cmd.redo ();
			undoable = true;
			redoable = history.hasNext();
		}
	}

	public void addProto(Command cmd) {
		protos.put(cmd.getName(), cmd);
	}

	public boolean undoable() {
		return undoable;
	}

	public boolean redoable() {
		return redoable;
	}
}
